#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <map>
using namespace std;

// 1. 初始化关键字
map<string, string> Map;
void initializeP()
{
    // 定义读写和运算
    Map["main"] = "MAINTK";
    Map["const"] = "CONSTTK";
    Map["int"] = "INTTK";
    Map["break"] = "BREAKTK";
    Map["continue"] = "CONTINUETK";
    Map["if"] = "IFTK";
    Map["else"] = "ELSETK";
    Map["while"] = "WHILETK";
    Map["getint"] = "GETINTTK"; 
    Map["printf"] = "PRINTFTK";
    Map["return"] = "RETURNTK";
    // 逻辑运算符
    Map["!"] = "NOT";
    Map["&&"] = "AND"; 
    Map["||"] = "OR"; 
    // 算术运算符
    Map["+"] = "PLUS";
    Map["-"] = "MINU";
    Map["*"] = "MULT";
    Map["/"] = "DIV";
    Map["%"] = "MOD";
    // 比较运算符
    Map["<"] = "LSS";
    Map["<="] = "LEQ";
    Map[">"] = "GRE";
    Map[">="] = "GEQ";
    Map["=="] = "EQL";
    Map["!="] = "NEQ";
    // 赋值运算符
    Map["="] = "ASSIGN";
    // 界符
    Map[";"] = "SEMICN";
    Map[","] = "COMMA";
    Map["("] = "LPARENT";
    Map[")"] = "RPARENT";
    Map["["] = "LBRACK";
    Map["]"] = "RBRACK";
    Map["{"] = "LBRACE";
    Map["}"] = "RBRACE";
    // 字符串
    Map["\""] = "STRCON";
    // 数字常量
    Map["INTCON"] = "INTCON";
    // 字符常量
    Map["void"] = "VOIDTK";
}

// 2. 读取文件数据
string input()
{ 
    string data;
    ifstream inFile;
    inFile.open("../test/testfile1.txt", ios::in);
    if (inFile)
    {
        printf("文件打开成功，正在读取文件数据\n");
        string buffer;
        while (getline(inFile, buffer))
        {
            data += buffer;
            data += '\n';
        }
        printf("数据读取完毕\n");
        inFile.close();
        printf("文件关闭\n");
    }
    return data;
}

// 3. 判断单词类别
bool isNumber(char c)
{ // 是否为整数
    if (c >= '0' && c <= '9')
        return true;
    else
        return false;
}
bool isUnder(char c)
{ // 是否为下划线
    if (c == '_')
        return true;
    else
        return false;
}
bool isLetter(char c)
{ // 是否是字母
    if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
        return true;
    else
        return false;
}
bool isDoubleSymbol(char c)
{ // 是否可为双个运算符
    if (c == '<' || c == '>' || c == '=' || c == '!' || c == '&' || c == '|')
        return true;
    else
        return false;
}
bool isSimpleSymbol(char c)
{ // 是否为单个运算符
    if (c == '+' ||  c == '-' || c == '*' || c == '/' || c == '%' || c == ';' || c == ',' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}')
        return true;
    else
        return false;
}
bool isStr(char c)
{ // 根据字符串开头为 " 进行开始判断
    if (c == '"')
        return true;
    else
        return false;
}

string JudgeKind(string c)
{ // 根据分过的单词来判断其类别
    string Kind;
    if (Map.find(c) != Map.end())
        Kind = Map[c];
    else
        Kind = "IDENFR";
    return Kind;
}

// 4. 分词
void WordDivision(vector<string> &data, vector<string> &data2, const char *str, int n)
{
    // 分词 data容器存储 单词类别码，data2容器存储 单词内容，实现token的词法分析的对应
    // 题目中共有 字符串 (STRCON)、字母单词类别 (IDENFR)，数字常量 (INTCON)
    for (int i = 0; i < n; i++)
    {
        // temp 存储 map 的 key 值（单词类别码），temp2 存储单词内容
        string temp;
        string temp2;
        if (str[i] == '/')
        {
            if (str[i + 1] == '/')
            { // 单行注释
                while (str[i] != '\n')
                    i++;
            }
            else if (str[i + 1] == '*')
            { // 多行注释
                while (!(str[i] == '*' && str[i + 1] == '/'))
                    i++;
                i+=2;
            }
        }
        if (isSimpleSymbol(str[i])) 
        { // 判断是否为单一运算符
            temp = str[i];
            temp2 = temp;
        }
        if (isDoubleSymbol(str[i]))
        { // 判断是否可为双个运算符
            temp += str[i];
            if (isDoubleSymbol(str[i + 1]))
            {
                temp += str[i + 1];
                i++;
            }
            temp2 = temp;
        }
        if (isStr(str[i]))
        { // 判断是否为字符串 (STRCON)
            temp2 += str[i];
            i++;
            while (!isStr(str[i]))
            {
                temp2 += str[i];
                i++;
            }
            temp2 += str[i];
            temp = "\"";
        }
        if (isNumber(str[i]))
        { // 判断是否为数字常量 (INTCON)
            temp = "INTCON";
            temp2 += str[i];
            i++;
            while (isNumber(str[i]))
            {
                temp2 += str[i];
                i++;
            }
            i--;
        }
        if (isLetter(str[i]) || isUnder(str[i]))
        { // 判断是否为字母或下划线 (IDENFR)
            temp += str[i];
            i++;
            while (isLetter(str[i]) || isNumber(str[i]) || isUnder(str[i]))
            {
                temp += str[i];
                i++;
            }
            i--;
            temp2 = temp;
        }
        if (temp != "")
        {
            data.push_back(JudgeKind(temp));
            data2.push_back(temp2);
        }
    }
}

// 5. 输出结果
int main()
{
    initializeP();
    string str = input();
    // 将std::string对象str转换为一个指向以空字符结尾的C字符串的指针，以便与使用C语言编写的函数或库进行交互
    // 可以被传递给接受C字符串作为参数的函数，这个指针指向的C字符串是只读的，因此声明为const char *类型
    const char *cstr = str.c_str();
    int n = str.length();
    cout << cstr << endl;
    vector<string> data;
    vector<string> data2;
    WordDivision(data, data2, cstr, n);

    ofstream outFile;
    outFile.open("output1.txt", ofstream::out);
    for (int i = 0; i < data.size(); i++)
    {
        outFile << data[i] << " " << data2[i] << endl;
    }
}

